package com.scrm.server.wx.cp.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.scrm.api.wx.cp.dto.*;
import com.scrm.api.wx.cp.entity.*;
import com.scrm.api.wx.cp.vo.*;
import com.scrm.common.config.ScrmConfig;
import com.scrm.common.constant.Constants;
import com.scrm.common.exception.BaseException;
import com.scrm.common.util.DateUtils;
import com.scrm.common.util.JwtUtil;
import com.scrm.common.util.ListUtils;
import com.scrm.common.util.UUID;
import com.scrm.server.wx.cp.dto.XxlJobInfoDTO;
import com.scrm.server.wx.cp.mapper.WxFissionTaskMapper;
import com.scrm.server.wx.cp.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 企微应用宝-裂变任务信息 服务实现类
 * @author xxh
 * @since 2022-03-21
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class WxFissionTaskServiceImpl extends ServiceImpl<WxFissionTaskMapper, WxFissionTask> implements IWxFissionTaskService {

    @Autowired
    private IStaffService staffService;

    @Autowired
    private IWxFissionCustomerService fissionCustomerService;

    @Autowired
    private IWxTempFileService tempFileService;

    @Autowired
    private IWxMsgTemplateService msgTemplateService;

    @Autowired
    private IWxFissionStageService fissionStageService;

    @Autowired
    private IContactWayService contactWayService;

    @Autowired
    private IWxContactExpirationService contactExpirationService;

    @Autowired
    private IWxFissionContactService wxFissionContactService;

    @Autowired
    private IWxCustomerStaffService customerStaffService;

    @Autowired
    private IXxlJobService xxlJobService;

    @Autowired
    private IWxTagService tagService;

    /**
     * 编辑时不能编辑的字段
     */
    private final String[] noUpdateParams = new String[]{"hasCheckDelete"};

    @Override
    public IPage<WxFissionTaskVO> pageList(WxFissionTaskPageDTO dto){
        LambdaQueryWrapper<WxFissionTask> wrapper = new QueryWrapper<WxFissionTask>()
        .lambda().eq(WxFissionTask::getExtCorpId, dto.getExtCorpId())
                .like(StringUtils.isNotBlank(dto.getName()), WxFissionTask::getName, dto.getName())
                .orderByDesc(WxFissionTask::getCreatedAt);
        IPage<WxFissionTask> page = page(new Page<>(dto.getPageNum(), dto.getPageSize()),wrapper);
        return page.convert(this::translation);
    }

    @Override
    public WxFissionTaskVO findById(String id){
        return translation(checkExists(id));
    }


    @Override
    public WxFissionTask save(WxFissionTaskSaveDTO dto){

        //封装数据
        WxFissionTask wxFissionTask = buildWxFissionTask(dto);

        //阶段奖励任务,
        List<WxFissionStage> fissionStage = fissionStageService.buildFissionStage(
                wxFissionTask.getId(), wxFissionTask.getExtCorpId(), wxFissionTask.getCodeExpiredTime(), dto.getStageSaveDTOS());

        //加入xxlJob定时任务
        wxFissionTask.setJobId(saveOrUpdateExpireTask(wxFissionTask));

        //入库
        save(wxFissionTask);
        fissionStageService.saveBatch(fissionStage);
        wxFissionContactService.saveSystem(wxFissionTask);

        //发送消息
        if (ListUtils.isNotEmpty(dto.getExtCustomerIds())) {
            sendExpandMsg(dto.getExtCorpId(), dto.getMsg(), dto.getExtCustomerIds());
        }

        return wxFissionTask;
    }

    private Integer saveOrUpdateExpireTask(WxFissionTask wxFissionTask){
        XxlJobInfoDTO xxlJobInfoDTO = new XxlJobInfoDTO();
        xxlJobInfoDTO.setId(wxFissionTask.getJobId()).setJobDesc("应用宝任务过期定时器")
                .setAuthor(wxFissionTask.getCreatorExtId())
                .setExecutorHandler(Constants.FISSION_TASK_EXPIRE_HANDLER)
                .setExecutorParam(wxFissionTask.getId()).setCron(DateUtils.getCron(wxFissionTask.getEndTime()));
        Integer jobId = xxlJobService.addOrUpdate(xxlJobInfoDTO);
        xxlJobService.start(jobId);
        return jobId;
    }

    /**
     * 封装对象需要的信息
     * @param dto
     * @return
     */
    private WxFissionTask buildWxFissionTask(WxFissionTaskSaveDTO dto) {
        WxFissionTask res = new WxFissionTaskVO();
        BeanUtils.copyProperties(dto, res);
        res.setId(UUID.get16UUID());

        checkParams(res);

        //封装返回对象
        res.setCreatedAt(new Date())
                .setUpdatedAt(new Date())
                .setCreatorExtId(JwtUtil.getExtUserId());

        //发送的消息，把链接补上去
        try {
            res.getMsg().getMedia().get(0).setHref(buildInviteLink(res));
        }catch (Exception e){
            log.error("新增企微宝任务失败，素材信息错误，[{}]", JSONObject.toJSONString(res.getMsg()), e);
            throw new BaseException("新增企微宝任务失败，素材信息错误");
        }
        return res;
    }

    /**
     * 参数校验
     * @param res
     */
    private void checkParams(WxFissionTask res) {

        if (count(new QueryWrapper<WxFissionTask>().lambda()
                .eq(WxFissionTask::getExtCorpId, res.getExtCorpId())
                .ne(WxFissionTask::getId, res.getId())
                .eq(WxFissionTask::getName, res.getName())) > 0) {
            throw new BaseException("该任务名已存在");
        }

        if (res.getEndTime().before(new Date())) {
            throw new BaseException("结束时间不能选之前的时间！");
        }

        if (res.getCodeExpiredTime().before(res.getEndTime())) {
            throw new BaseException("二维码有效期不能早于结束时间");
        }
    }


    @Override
    public WxFissionTask update(WxFissionTaskUpdateDTO dto){

        //校验参数
        WxFissionTask old = checkExists(dto.getId());

        WxFissionTask update = updateWxFissionTask(old, dto);

        //更新阶段数据，先删后增
        if (old.getStatus().equals(WxFissionTask.STATUS_NO_START)) {
            fissionStageService.updateFissionStage(old.getId(), old.getExtCorpId(), dto.getCodeExpiredTime(), dto.getStageSaveDTOS());
        }

        //发送消息
        if (ListUtils.isNotEmpty(dto.getExtCustomerIds())) {
            sendExpandMsg(dto.getExtCorpId(), dto.getMsg(), dto.getExtCustomerIds());
        }

       return update;
    }

    /**
     * 更新企微宝任务
     * @param old
     * @param dto
     */
    private WxFissionTask updateWxFissionTask(WxFissionTask old, WxFissionTaskUpdateDTO dto) {

        checkParams(old, dto);

        //看有没有换员工
        if (!ListUtils.isSame(old.getExtStaffIds(), dto.getExtStaffIds())) {
            wxFissionContactService.updateStaffIds(dto.getExtCorpId(), dto.getId(), dto.getExtStaffIds());
        }

        //更新
        WxFissionTask update = new WxFissionTask();
        BeanUtils.copyProperties(old, update);
        BeanUtils.copyProperties(dto, update, noUpdateParams);

        checkParams(update);

        update.setUpdatedAt(new Date());

        update.setJobId(saveOrUpdateExpireTask(update));

        updateById(update);

        return update;
    }

    /**
     * 检查更新的参数
     * @param old
     * @param dto
     */
    private void checkParams(WxFissionTask old, WxFissionTaskUpdateDTO dto) {
        if (dto.getStatus() < old.getStatus()) {
            throw new BaseException("更新不允许修改");
        }
    }


    @Override
    public void delete(String id){

        //校验参数
        WxFissionTask wxFissionTask = checkExists(id);

        if (wxFissionTask.getStatus().equals(WxFissionTask.STATUS_START)) {
            throw new BaseException("该任务进行中，无法删除！");
        }

        //删除
        removeById(id);

    }

    /**
     * 翻译
     * @param wxFissionTask 实体
     * @return WxFissionTaskVO 结果集
     * @author xxh
     * @date 2022-03-21
     */
    private WxFissionTaskVO translation(WxFissionTask wxFissionTask){
        WxFissionTaskVO res = new WxFissionTaskVO();
        BeanUtils.copyProperties(wxFissionTask, res);

        //创建者信息
        res.setCreatorInfo(staffService.find(wxFissionTask.getExtCorpId(), wxFissionTask.getCreatorExtId()));

        //参与员工
        List<Staff> staffList = staffService.list(new QueryWrapper<Staff>().lambda()
                .in(Staff::getExtCorpId, res.getExtCorpId())
                .in(Staff::getExtId, res.getExtStaffIds()));

        res.setStaffVOList(staffList);

        //添加客户数
        long count = fissionCustomerService.count(new QueryWrapper<WxFissionCustomer>().lambda()
                .eq(WxFissionCustomer::getExtCorpId, res.getExtCorpId())
                .eq(WxFissionCustomer::getTaskId, res.getId()));

        res.setCount((int) count);

        //海报信息
        WxTempFile posterFile = tempFileService.getById(res.getPosterFileId());
        res.setPosterFile(posterFile);

         //邀请链接
        res.setInviteLink(buildInviteLink(res));

        //各个阶段的设置
        List<WxFissionStageVO> wxFissionStageVOS = fissionStageService.queryList(new WxFissionStageQueryDTO()
                .setExtCorpId(res.getExtCorpId()).setTaskId(res.getId()));
        res.setWxFissionStageVOS(wxFissionStageVOS);

        //获取系统默认的渠道活码
        WxFissionContact contact = wxFissionContactService.getSysContact(res.getExtCorpId(), res.getId());
        res.setQrCode(contact.getQrCode());

        //标签
        res.setTagList(tagService.getNameByIds(res.getTags()));

        return res;
    }


    /**
     * 构造邀请参与活动的链接
     * @param task
     * @return
     */
    private String buildInviteLink(WxFissionTask task) {
        return ScrmConfig.getFissionEventUrl() + "?taskId=" + task.getId() + "&corpId=" + task.getExtCorpId();
    }


    @Override
    public WxFissionTask checkExists(String id){
        if (StringUtils.isBlank(id)) {
            return null;
        }
        WxFissionTask byId = getById(id);
        if (byId == null) {
            throw new BaseException("企微应用宝-裂变任务信息不存在");
        }
        return byId;
    }

    @Override
    public WxFissionTask checkExistsIncludeDel(String id) {
        return baseMapper.find(id);
    }

    @Override
    public void over(String id) {
        WxFissionTask wxFissionTask = checkExists(id);

        wxFissionTask.setStatus(WxFissionTask.STATUS_OVER)
                .setEndTime(new Date())
                .setUpdatedAt(new Date());

        updateById(wxFissionTask);

        //即刻失效
        if (wxFissionTask.getCodeExpiredDays() == 0) {
            contactExpirationService.handleExpiration(wxFissionTask.getExtCorpId(), wxFissionTask.getId());
        }else{

            //还有二维码的失效
            Calendar instance = Calendar.getInstance();
            instance.add(Calendar.DATE, wxFissionTask.getCodeExpiredDays());
            contactExpirationService.createJob(wxFissionTask.getExtCorpId(), wxFissionTask.getId(), instance.getTime());

        }
    }

    @Override
    public WxFissionTaskCountVO countByCondition(WxFissionCountConditionVO conditionVO) {

        long customerNum = 0;

        //参与客户数,传了ExtCustomerId表明是详情里的，详情里不用查这个数据
        if (StringUtils.isBlank(conditionVO.getExtCustomerId())) {
            customerNum = wxFissionContactService.count(new
                    QueryWrapper<WxFissionContact>().lambda()
                    .eq(WxFissionContact::getExtCorpId, conditionVO.getExtCorpId())
                    .eq(WxFissionContact::getTaskId, conditionVO.getId())
                    .eq(WxFissionContact::getHasSystem, false));
        }

        //统计其他数据
        List<WxFissionCustomer> customerList = fissionCustomerService.list(new QueryWrapper<WxFissionCustomer>().lambda()
                .select(WxFissionCustomer::getHasDeleted,
                        WxFissionCustomer::getCreatedAt,
                        WxFissionCustomer::getHasFirst)
                .eq(WxFissionCustomer::getExtCorpId, conditionVO.getExtCorpId())
                .eq(WxFissionCustomer::getTaskId, conditionVO.getId())
                .eq(StringUtils.isNotBlank(conditionVO.getExtCustomerId()), WxFissionCustomer::getExtInviteCustomerId, conditionVO.getExtCustomerId()));

        int lose = 0;
        int today = 0;
        int success = 0;

        //获取今天0点
        Calendar todayCalendar = Calendar.getInstance();
        todayCalendar.set(Calendar.HOUR, 0);
        todayCalendar.set(Calendar.MINUTE, 0);
        todayCalendar.set(Calendar.SECOND, 0);
        Date todayTime = todayCalendar.getTime();

        for (WxFissionCustomer customer : customerList) {

            if (customer.getHasDeleted()) {
                lose ++;
            }

            if (customer.getHasFirst()) {
                success ++;
            }

            if (todayTime.before(customer.getCreatedAt())) {
                today ++;
            }
        }
        return new WxFissionTaskCountVO().setCustomerNum((int) customerNum)
                .setAddCustomerNum(customerList.size())
                .setLoseCustomerNum(lose)
                .setTodayAddCustomerNum(today)
                .setSuccessNum(success);
    }

    @Override
    public void expand(FissionExpandDTO dto) {
        WxFissionTask wxFissionTask = checkExists(dto.getTaskId());

        sendExpandMsg(dto.getExtCorpId(), wxFissionTask.getMsg(), dto.getExtCustomerIds());
    }

    @Override
    public List<String> findUnOverTask(String extCorpId) {
        List<WxFissionTask> list = list(new QueryWrapper<WxFissionTask>().lambda()
                .select(WxFissionTask::getId)
                .eq(WxFissionTask::getExtCorpId, extCorpId)
                .ne(WxFissionTask::getStatus, WxFissionTask.STATUS_OVER));

        if (ListUtils.isEmpty(list)) {
            return null;
        }

        return list.stream().map(WxFissionTask::getId).collect(Collectors.toList());
    }

    private void sendExpandMsg(String extCorpId, WxMsgDTO msg, List<String> extCustomerIds) {

        //先查出来是哪个员工发
        List<WxCustomerStaff> customerStaffList = customerStaffService.list(new QueryWrapper<WxCustomerStaff>().lambda()
                .eq(WxCustomerStaff::getExtCorpId, extCorpId)
                .in(WxCustomerStaff::getExtCustomerId, extCustomerIds));

        if (ListUtils.isEmpty(customerStaffList)) {
            log.error("推广客户，发送消息为空, [{}], [{}]", extCorpId, JSON.toJSONString(extCustomerIds));
            return;
        }

        Map<String, List<WxCustomerStaff>> staffCustomerMap = customerStaffList.stream().collect(Collectors.groupingBy(WxCustomerStaff::getExtStaffId));

        staffCustomerMap.forEach((extStaffId, list) -> {

            List<String> customerIds = list.stream().map(WxCustomerStaff::getExtCustomerId).collect(Collectors.toList());
            msgTemplateService.commonSendMsg(msg, extStaffId, customerIds, extCorpId);

        });
    }

}
